/*
 * Copyright 2011 Katsunori Koyanagi
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package sweezy.swf.tools.abcdump
{
	import sweezy.swf.abc.structure.ConstTrait;
	import sweezy.swf.abc.structure.NamespaceInfo;
	import sweezy.swf.abc.structure.QNameInfo;
	import sweezy.swf.abc.structure.SlotTrait;
	import sweezy.swf.abc.structure.TraitInfo;
	import sweezy.swf.constant.NamespaceKind;
	import sweezy.swf.constant.TraitAttributes;

	internal class VariableDef extends ABCElementDef
	{

		private var _const:ConstTrait;

		private var _isStatic:Boolean;

		private var _slot:SlotTrait;

		public function VariableDef(container:ABCcontainerDef, object:Object, isStatic:Boolean)
		{
			super(container);

			_isStatic = isStatic;
			if (object is SlotTrait)
			{
				_slot = object as SlotTrait;
			}
			else if (object is ConstTrait)
			{
				_const = object as ConstTrait;
			}
		}

		override public function dump(stream:IDumpStream):void
		{
			dumpMetadataDefs(stream);

			var result:String = "";

			var namespace:Namespace = this.namespace;
			if (namespace !== null)
			{
				result += namespace;
				result += " ";
			}
			if (_isStatic)
			{
				result += "static ";
			}
			if (_const !== null)
			{
				result += "const ";
			}
			else
			{
				result += "var ";
			}
			result += name;
			result += ":";
			result += type;

			if (hasValue)
			{
				result += " = ";
				result += getValueString();
			}

			result += ";";

			var slotId:uint = 0;
			if (_slot !== null)
			{
				slotId = _slot.slotId;
			}
			else if (_const !== null)
			{
				slotId = _const.slotId;
			}
			result += " //slot_id=";
			result += slotId;
			stream.println(result);
		}

		public function get name():String
		{
			var qname:QNameInfo = getQname();
			if (qname === null)
			{
				return "";
			}

			if (qname.name === 0)
			{
				return "";
			}

			return _constantPool.stringConstants[qname.name];
		}

		public function get namespace():Namespace
		{
			var qname:QNameInfo = getQname();
			if (qname === null)
			{
				return null;
			}

			var namespace:NamespaceInfo = _constantPool.namespaceInfos[qname.ns] as NamespaceInfo;
			if (namespace === null)
			{
				return null;
			}

			switch (namespace.kind)
			{
				case NamespaceKind.NAMESPACE:
					return new Namespace(_constantPool.stringConstants[namespace.name]);
				case NamespaceKind.PACKAGE_INTERNAL_NS:
					return Utils.INTERNAL;
				case NamespaceKind.PRIVATE_NS:
					return Utils.PRIVATE;
				case NamespaceKind.PACKAGE_NAMESPACE:
					return Utils.PUBLIC;
				case NamespaceKind.PROTECTED_NAMESPACE:
					return Utils.PROTECTED;
			}

			return null;
		}

		private function dumpMetadataDefs(stream:IDumpStream):void
		{
			var trait:TraitInfo = _slot !== null ? _slot : _const !== null ? _const : null;
			if (trait !== null && (trait.attributes & TraitAttributes.METADATA) === TraitAttributes.METADATA)
			{
				for each (var index:uint in trait.metadata)
				{
					new MetadataDef(_container, _abc.metadataInfos[index]).dump(stream);
				}
			}
		}

		private function getQname():QNameInfo
		{
			var name:uint = 0;

			if (_const !== null)
			{
				name = _const.name;
			}
			else if (_slot !== null)
			{
				name = _slot.name;
			}
			if (name === 0)
			{
				return null;
			}

			return _constantPool.multinameInfos[name] as QNameInfo;
		}

		private function getValueString():String
		{
			var index:uint = 0;
			var kind:uint;
			if (_slot !== null)
			{
				index = _slot.vIndex;
				kind = _slot.vKind;
			}
			else if (_const !== null)
			{
				index = _const.vIndex;
				kind = _const.vKind;
			}

			return Utils.getConstantValueToString(_constantPool, index, kind);
		}

		private function get hasValue():Boolean
		{
			if (_slot !== null)
			{
				return _slot.vIndex > 0;
			}
			else if (_const !== null)
			{
				return _const.vIndex > 0;
			}

			return false;
		}

		private function get type():String
		{
			var name:uint = 0;
			if (_const !== null)
			{
				name = _const.typeName;
			}
			else if (_slot !== null)
			{
				name = _slot.typeName;
			}

			if (name === 0)
			{
				return "*";
			}

			return Utils.multinameToString(_constantPool, name);
		}

		private function get value():*
		{
			var index:uint = 0;
			var kind:uint;
			if (_slot !== null)
			{
				index = _slot.vIndex;
				kind = _slot.vKind;
			}
			else if (_const !== null)
			{
				index = _const.vIndex;
				kind = _const.vKind;
			}

			return Utils.getConstantValue(_constantPool, index, kind);
		}
	}
}
